use alloc::{collections::{BTreeSet, LinkedList}, string::{String, ToString}, sync::Arc};
use core::{cell::RefCell, cmp::Ordering, ffi::c_void, ptr::null};

use crate::{clock::rt_tick_get, irq::{rt_hw_interrupt_disable, rt_hw_interrupt_enable}, object::*};
use crate::rt_extern::*;

#[derive(Debug, PartialEq)]
pub enum TimerFlag {
    RtTimerFlagOneShot,
    RtTimerFlagPeriodic
}

#[derive(Debug, PartialEq)]
pub enum TimerStatus {
    RtTimerFlagDeactivated,
    RtTimerFlagActivated
}

#[derive(Debug, PartialEq)]
pub enum TimerTypes {
    RtTimerFlagHardTimer,
    RtTimerFlagSoftTimer
}

const RT_TIMER_CTRL_SET_TIME          :u8 = 0x0;             // < set timer control command 
const RT_TIMER_CTRL_GET_TIME          :u8 = 0x1;             // < get timer control command 
const RT_TIMER_CTRL_SET_ONESHOT       :u8 = 0x2;             // < change timer to one shot 
const RT_TIMER_CTRL_SET_PERIODIC      :u8 = 0x3;             // < change timer to periodic 
const RT_TIMER_CTRL_GET_STATE         :u8 = 0x4;             // < get timer run state active or deactive


/// 定时器tree，对应rt-thread中的定时器表，BTree的数据结构便于查找有序的定时器。 
pub static mut RT_TIMER_TREE: BTreeSet<Arc<RefCell<RtTimer>>> = BTreeSet::new();

fn get_first_timer() -> Option<Arc<RefCell<RtTimer>>> {
    unsafe {
        RT_TIMER_TREE.pop_first()
    } 
}

#[derive(Debug)]
pub struct RtTimer {
    parent: RtObject,
    timeout_func: Option<fn(*const c_void)>,
    parameter: *const c_void,

    flag: TimerFlag,
    types: TimerTypes,
    status: TimerStatus,

    init_tick: usize,
    timeout_tick: usize,
}

impl PartialEq for RtTimer {
    fn eq(&self, other: &Self) -> bool {
        self.timeout_tick == other.timeout_tick
    }
}

impl PartialOrd for RtTimer {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.timeout_tick.cmp(&other.timeout_tick))
    }
}

impl Eq for RtTimer { }

impl Ord for RtTimer {
    fn cmp(&self, other: &Self) -> Ordering {
        self.timeout_tick.cmp(&other.timeout_tick)
    }
}

impl Drop for RtTimer {
    fn drop(&mut self) {
        self.timeout_func = None;
        self.parameter = null();
    }
}


impl RtTimer {
    pub fn new(name: String, t: RtObjectClassType) -> Self {
        RtTimer {
            parent: RtObject::new(name, t),
            timeout_func: None,
            parameter: null(),

            status: TimerStatus::RtTimerFlagDeactivated,
            flag: TimerFlag::RtTimerFlagOneShot,
            types: TimerTypes::RtTimerFlagSoftTimer,

            init_tick: 0,
            timeout_tick: 0,
        }
    }

    pub fn set_parameter(&mut self, parameter: *const c_void) {
        self.parameter = parameter;
    }

    pub fn finish(&self) -> bool {
        self.timeout_tick <= rt_tick_get()
    }

    pub fn is_active(&self) -> bool {
        self.status == TimerStatus::RtTimerFlagActivated
    }

    pub fn is_periodic(&self) -> bool {
        self.flag == TimerFlag::RtTimerFlagPeriodic
    }

    pub fn active(&mut self) {
        self.status = TimerStatus::RtTimerFlagActivated
    }

    pub fn deactive(&mut self) {
        self.status = TimerStatus::RtTimerFlagDeactivated
    }

    pub fn set_oneshot(&mut self) {
        self.flag = TimerFlag::RtTimerFlagOneShot
    }

    pub fn set_periodic(&mut self) {
        self.flag = TimerFlag::RtTimerFlagPeriodic
    }

    pub fn func(mut self, timeout_func: Option<fn(*const c_void)>, parameter: *const c_void) -> Self {
        self.timeout_func = timeout_func;
        self.parameter = parameter;
        self
    }

    pub fn exec(&self) {
        if let Some(func) = self.timeout_func {
            func(self.parameter)
        }
    }

    pub fn tick(mut self, init_tick: usize) -> Self {
        self.init_tick = init_tick;
        self
    }

    pub fn set_tick(&mut self, tick: usize) {
        self.init_tick = tick;
    }

    pub fn set_timeout_tick(&mut self) {
        self.timeout_tick = self.init_tick + rt_tick_get()
    }
}

pub fn rt_timer_new(name: String, 
    timeout_func: Option<fn(*const c_void)>, 
    parameter: *const c_void, 
    time: usize, 
    flag: TimerFlag
) -> Arc<RefCell<RtTimer>> {
    let mut t = RtTimer::new(name, RtObjectClassType::RtObjectClassTimer)
    .func(timeout_func, parameter)
    .tick(time);
    if flag == TimerFlag::RtTimerFlagPeriodic {
        t.set_periodic();
    }
    Arc::new(RefCell::new(t))
}

fn _rt_timer_insert(timer: Arc<RefCell<RtTimer>>) {
    unsafe {
        RT_TIMER_TREE.insert(timer);
    }
}

fn _rt_timer_remove(timer: &Arc<RefCell<RtTimer>>) {
    unsafe {
        RT_TIMER_TREE.remove(timer);
    }
}

pub fn rt_timer_start(timer: Arc<RefCell<RtTimer>>) {
    let level = unsafe { rt_hw_interrupt_disable() };
    
    _rt_timer_remove(&timer);

    timer.borrow_mut().set_timeout_tick();

    _rt_timer_insert(timer.clone());

    timer.borrow_mut().active();
    
    unsafe { rt_hw_interrupt_enable(level) };
}

pub fn rt_timer_stop(timer: Arc<RefCell<RtTimer>>) -> Result<(), RtErrCode> {
    if !timer.borrow().is_active() {
        return Err(RtErrCode::RtError);
    } 

    let level = unsafe { rt_hw_interrupt_disable() };

    _rt_timer_remove(&timer);

    unsafe { rt_hw_interrupt_enable(level) };

    timer.borrow_mut().deactive();

    Ok(())
}

pub fn rt_timer_detach(timer: &Arc<RefCell<RtTimer>>) {
    let level = unsafe { rt_hw_interrupt_disable() };

    _rt_timer_remove(&timer);

    timer.borrow_mut().deactive();

    unsafe { rt_hw_interrupt_enable(level) };
}

pub fn rt_timer_check() {
    let level = unsafe { rt_hw_interrupt_disable() }; 

    while let Some(timer) = get_first_timer() {
        if timer.borrow().finish() {
            timer.borrow().exec();
        } else {
            _rt_timer_insert(timer);
            break;
        }

        let f = timer.borrow().is_periodic();

        if f {
            rt_timer_start(timer);
        } else {
            timer.borrow_mut().deactive();
        }

    }

    unsafe { rt_hw_interrupt_enable(level) };
}

